namespace SimpleWebServices.Security.Principal
{
    using System;
    using System.Web;
    using System.Xml.XPath;
    using SimpleWebServices;
    using SimpleWebServices.Data;
    using SimpleWebServices.Security.Cryptography;
    using Xunit;

    public sealed class AuthenticationRecordFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<AuthenticationRecord>()
                .DerivesFrom<SimpleWebServices.Data.Record>()
                .IsAbstractBaseClass()
                .XmlRoot("authentication")
                .Result);
        }

        [Fact]
        public void deserialize()
        {
            TestAuthenticationRecord obj = (
                "<authentication>" +
                    "<data>" +
                        "<value name='ip'>127.0.0.1</value>" +
                    "</data>" +
                "</authentication>").Deserialize<TestAuthenticationRecord>();

            Assert.Equal<string>("127.0.0.1", obj.Data["ip"]);
        }

        [Fact]
        public void deserializeEmpty()
        {
            TestAuthenticationRecord actual = "<authentication />".Deserialize<TestAuthenticationRecord>();

            Assert.NotNull(actual.Data);
        }

        [Fact]
        public void serialize()
        {
            TestAuthenticationRecord obj = new TestAuthenticationRecord();
            obj.Data.Add("ip", "127.0.0.1");

            XPathNavigator navigator = obj.Serialize().CreateNavigator();

            Assert.True((bool)navigator.Evaluate("'127.0.0.1'=/authentication/data/value[@name='ip']"));
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new TestAuthenticationRecord());
        }

        [Fact]
        public void prop_ExpirationCookie()
        {
            try
            {
                DateTimeFactory.Mock = DateTime.UtcNow;

                HttpCookie actual = TestAuthenticationRecord.ExpirationCookie;

                Assert.Equal<DateTime>(DateTimeFactory.UtcNow.AddDays(-1), actual.Expires);
                Assert.Equal<string>("Authentication", actual.Name);
                Assert.Null(actual.Value);
            }
            finally
            {
                DateTimeFactory.Reset();
            }
        }

        [Fact]
        public void prop_Data()
        {
            Assert.True(new PropertyExpectations(typeof(TestAuthenticationRecord).GetProperty("Data"))
                .XmlElement("data")
                .TypeIs<DataCollection>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_Entity()
        {
            Assert.True(new PropertyExpectations(typeof(TestAuthenticationRecord).GetProperty("Entity"))
                .XmlIgnore()
                .TypeIs<string>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_Entity_get()
        {
            TestAuthenticationRecord obj = (
                "<authentication>" +
                    "<data>" +
                        "<value name='ip'>127.0.0.1</value>" +
                    "</data>" +
                "</authentication>").Deserialize<TestAuthenticationRecord>();

            string expected = "NGf9vGl2umFMjlWJk0qj9g==";
            string actual = MD5Hash.Compute(obj.Entity);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Entity_getEmpty()
        {
            string expected = string.Empty;
            string actual = new TestAuthenticationRecord().Entity;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_FormatUrn_Token()
        {
            Token token = Token.New();

            AbsoluteUri expected = "urn://authentication/" + token;
            AbsoluteUri actual = TestAuthenticationRecord.FormatUrn(token);

            Assert.Equal<AbsoluteUri>(expected, actual);
        }

        [Fact]
        public void op_FormatUrn_TokenEmpty()
        {
            Assert.Throws<ArgumentOutOfRangeException>(() => TestAuthenticationRecord.FormatUrn(Token.Empty));
        }
    }
}